package ink.xiaobaibai.controller.monthly;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import ink.xiaobaibai.common.AddTimeTaskBo;
import ink.xiaobaibai.common.MySecurity;
import ink.xiaobaibai.common.TimedTask;
import ink.xiaobaibai.entity.*;
import ink.xiaobaibai.enumOxy.MonthlyfeeOrderStatus;
import ink.xiaobaibai.multipleClick.ForbidMultipleClick;
import ink.xiaobaibai.response.ResponseCode;
import ink.xiaobaibai.response.ResponseFormat;
import ink.xiaobaibai.service.*;
import ink.xiaobaibai.service.monthly.IDelayTimedTaskService;
import ink.xiaobaibai.serviceOxy.ISmsService;
import ink.xiaobaibai.serviceOxy.monthly.IDeviceMonControlService;
import ink.xiaobaibai.serviceOxy.monthly.IOrderMonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @description: 月费机器控制层
 * @author: 小白白
 * @create: 2021-05-30
 **/

@RestController
@RequestMapping("/monthlyfee/device")
@Api(tags = "月费机器")
public class DeviceController {

    public static final String monDStatus = "monDStatus";

    @Autowired
    private IMonthlyUserDeviceService userDeviceService;

    @Autowired
    private IDeviceMonControlService deviceMonControlService;

    @Autowired
    private IOrderMonService orderMonService;

    @Autowired
    private IMonthlyTimedTaskService timedTaskService;

    @Autowired
    private IDelayTimedTaskService delayTimedTaskService;

    @Autowired
    private IMonthlyfeeDeviceService monthlyfeeDeviceService;

    @Autowired
    private IJumpService_V2 jumpService_v2;

    @Autowired
    private IMonthlyfeeOrderService monthlyfeeOrderService;

    @Autowired
    private IAdminUserService adminUserService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ISmsService smsService;

    /**
     * 查看自己的月费机器列表 (即使用中的订单的机器)
     */
    @GetMapping("/list")
    @ApiOperation("查看自己的月费机器列表")
    public ResponseFormat getDeviceList() {
        Integer userId = MySecurity.getUserId();
        QueryWrapper<MonthlyUserDevice> q1 = new QueryWrapper<>();
        q1.select("device_id", "can_use", "trusteeship");
        q1.eq("user_id", userId);
        List<MonthlyUserDevice> list = this.userDeviceService.list(q1);
        if (list.size() != 0) {
            Map<Integer, MonthlyUserDevice> map = new HashMap<>(list.size());
            List<Integer> ids = new ArrayList<>(list.size());
            for (MonthlyUserDevice device : list) {
                ids.add(device.getDeviceId());
                map.put(device.getDeviceId(), device);
            }

            QueryWrapper<MonthlyfeeDevice> q0 = new QueryWrapper<>();
            q0.select("id", "device_code");
            q0.in("id", ids);
            List<MonthlyfeeDevice> deviceList = this.monthlyfeeDeviceService.list(q0);
            for (int i = 0; i < deviceList.size(); i++) {
                map.get(deviceList.get(i).getId()).setDeviceCode(deviceList.get(i).getDeviceCode());
            }

            // 剩余多久可以使用+负责人信息
            Map<Integer, AdminUser> adminUserMap = new HashMap<>();
            QueryWrapper<MonthlyfeeOrder> q2 = new QueryWrapper<>();
            q2.select("device_id", "expire_time", "admin_user_id");
            q2.eq("user_id", userId);
            q2.ge("expire_time", new Date());
            q2.in("device_id", ids);
            List<MonthlyfeeOrder> orderList = this.monthlyfeeOrderService.list(q2);
            for (MonthlyfeeOrder order : orderList) {
                MonthlyUserDevice monthlyUserDevice = map.get(order.getDeviceId());
                AdminUser adminUser = adminUserMap.get(order.getAdminUserId());
                if (adminUser == null) {
                    QueryWrapper<AdminUser> q3 = new QueryWrapper<>();
                    q3.select("user_name", "user_phone");
                    q3.eq("id", order.getAdminUserId());
                    adminUser = this.adminUserService.getOne(q3);
                    if (adminUser != null) {
                        adminUserMap.put(order.getUserId(), adminUser);
                        monthlyUserDevice.setAdminName(adminUser.getUserName());
                        monthlyUserDevice.setAdminPhone(adminUser.getUserPhone());
                    }
                } else {
                    monthlyUserDevice.setAdminName(adminUser.getUserName());
                    monthlyUserDevice.setAdminPhone(adminUser.getUserPhone());
                }
                if (monthlyUserDevice != null) {
                    monthlyUserDevice.setExpireTime(order.getExpireTime());
                }
                QueryWrapper<MonthlyTimedTask> q4 = new QueryWrapper<>();
                q4.select("open");
                q4.eq("device_id", monthlyUserDevice.getDeviceId());
                MonthlyTimedTask timedTask = this.timedTaskService.getOne(q4);
                if (timedTask != null && timedTask.getOpen()) {
                    monthlyUserDevice.setStatus("定时中");
                    continue;
                }
                String time = this.stringRedisTemplate.opsForValue().get(monDStatus + monthlyUserDevice.getDeviceId());
                if (time != null) {
                    monthlyUserDevice.setStatus("运行中");
                    monthlyUserDevice.setStopTime(time);
                } else {
                    monthlyUserDevice.setStatus("空闲中");
                }
            }
        }


        return ResponseFormat.success(list);
    }

    @GetMapping("/item/{id}")
    @ApiOperation("当前包月机器的详细信息|| 是否开启了定时任务 || 是否开启了托管(trusteeship属性)")
    public ResponseFormat getDeviceItem(@PathVariable("id") Integer deviceId) {
        /**
         * 是否定时任务进行中  是否正在启动状态
         */
        JSONObject jsonObject = new JSONObject();
        QueryWrapper<MonthlyUserDevice> q1 = new QueryWrapper<>();
        q1.eq("device_id", deviceId);
        MonthlyUserDevice monthlyUserDevice = this.userDeviceService.getOne(q1);

        QueryWrapper<MonthlyfeeDevice> q2 = new QueryWrapper<>();
        q2.select("admin_user_id", "device_code");
        q2.eq("id", deviceId);
        MonthlyfeeDevice monthlyfeeDevice = this.monthlyfeeDeviceService.getOne(q2);
        monthlyUserDevice.setDeviceCode(monthlyfeeDevice.getDeviceCode());

        QueryWrapper<AdminUser> q3 = new QueryWrapper<>();
        q3.select("user_name", "user_phone");
        q3.eq("id", monthlyfeeDevice.getAdminUserId());
        AdminUser adminUser = this.adminUserService.getOne(q3);
        monthlyUserDevice.setAdminName(adminUser.getUserName());
        monthlyUserDevice.setAdminPhone(adminUser.getUserPhone());

        QueryWrapper<MonthlyfeeOrder> q35 = new QueryWrapper<>();
        q35.select("expire_time");
        q35.eq("device_id", deviceId);
        q35.eq("user_id", MySecurity.getUserId());
        q35.eq("status", MonthlyfeeOrderStatus.INUSE.getStatus());
        MonthlyfeeOrder order = this.monthlyfeeOrderService.getOne(q35);

        if (order != null) {
            monthlyUserDevice.setExpireTime(order.getExpireTime());
        }

        QueryWrapper<MonthlyTimedTask> q4 = new QueryWrapper<>();
        q4.eq("device_id", monthlyUserDevice.getDeviceId());
        MonthlyTimedTask timedTask = this.timedTaskService.getOne(q4);
        jsonObject.put("monthlyTimedTask", timedTask);
        if (timedTask != null && timedTask.getOpen()) {
            monthlyUserDevice.setStatus("定时中");
        } else {
            String time = this.stringRedisTemplate.opsForValue().get(monDStatus + monthlyUserDevice.getDeviceId());
            if (time != null) {
                monthlyUserDevice.setStatus("运行中");
                monthlyUserDevice.setStopTime(time);
                // 加个运行时间的截止时间
            } else {
                monthlyUserDevice.setStatus("空闲中");
            }
        }

        jsonObject.put("monthlyUserDevice", monthlyUserDevice);
        return ResponseFormat.success(jsonObject);
    }

    /**
     * 启动自己的机器
     * 多少分钟后关闭
     */
    @GetMapping("/open")
    @ApiOperation("启动自己的机器")
    public ResponseFormat openMyDevice(@RequestParam("deviceId") Integer deviceId,
                                       @RequestParam("seconds") Integer seconds) {
        if (seconds <= 0) {
            return ResponseFormat.failure("错误的时间设置");
        }
        Integer userId = MySecurity.getUserId();
        //如果当前机器是定时任务状态
        if (this.isTimeTaskDevice(deviceId)) {
            return ResponseFormat.fail("请先将定时任务关闭,才可进行单次控制");
        }
        //是否为自己的机器&&机器可用
        MonthlyUserDevice userDevice = this.getUserDevice(userId, deviceId);
        if (userDevice == null) {
            return ResponseFormat.fail("机器不可用");
        }
//        if(!jumpService_v2.checkMonthlyDeviceOnLine(deviceId)){
//            return ResponseFormat.fail("当前机器已断线");
//        }
        //月费机器可以重复启动,因为这样可以避免出现事故,允许重复启动
//        if(userDevice.getDeviceOpen()){
//            return ResponseFormat.fail("机器已在启动中");
//        }
        //启动机器
        this.deviceMonControlService.openDevice(deviceId, seconds);
        this.stringRedisTemplate.opsForValue().set(monDStatus + deviceId, DateUtils.addSeconds(new Date(), seconds).toString(), seconds, TimeUnit.SECONDS);
        //检验是否激活,没有就去激活
//        orderMonService.activateDevice(deviceId,userId);
        return ResponseFormat.success();
    }

    /**
     * 立即关闭自己的机器
     */
    @GetMapping("/close")
    @ApiOperation("关闭自己的机器")
    public ResponseFormat closeMyDevice(@RequestParam("deviceId") Integer deviceId) {
        Integer userId = MySecurity.getUserId();
        //查询是否为自己的机器
        MonthlyUserDevice userDevice = this.getUserDevice(userId, deviceId);
        if (userDevice == null) {
            return ResponseFormat.fail("机器不可用");
        }
        //如果当前机器是定时任务状态
        if (this.isTimeTaskDevice(deviceId)) {
            return ResponseFormat.fail("请先将定时任务关闭,才可进行单次控制");
        }
//        if(!jumpService_v2.checkMonthlyDeviceOnLine(deviceId)){
//            return ResponseFormat.fail("当前机器已断线");
//        }
        this.deviceMonControlService.closeDeviceAtOnce(deviceId);
        this.stringRedisTemplate.delete(monDStatus + deviceId);

        return ResponseFormat.success();
    }

    /**
     * 当前机器的定时任务
     */
    @GetMapping("/timed-task/{deviceId}")
    @ApiOperation("查看当前机器的定时任务")
    public ResponseFormat getTimedTaskByDeviceId(@PathVariable("deviceId") Integer deviceId) {
        QueryWrapper<MonthlyTimedTask> q1 = new QueryWrapper<>();
        q1.eq("device_id", deviceId);
        MonthlyTimedTask timedTask = this.timedTaskService.getOne(q1);
        return ResponseFormat.success(timedTask);
    }

    /**
     * 授权托管 关闭则开启,开启则关闭
     * (托管只是后台可以更改你的定时任务罢了)
     */
    @PutMapping("/trusteeship/{deviceId}")
    @ApiOperation("开启或者关闭托管,传入机器id | 关闭则开启,开启则关闭")
    @ForbidMultipleClick(key = "#deviceId", prefixUserId = true)
    public ResponseFormat trusteeship(@PathVariable Integer deviceId) {
        Integer userId = MySecurity.getUserId();
        QueryWrapper<MonthlyUserDevice> q1 = new QueryWrapper<>();
        q1.eq("user_id", userId);
        q1.eq("device_id", deviceId);
        MonthlyUserDevice userDevice = this.userDeviceService.getOne(q1);
        if (userDevice == null) {
            return ResponseFormat.fail("当前机器不存在");
        }
        UpdateWrapper<MonthlyUserDevice> u1 = new UpdateWrapper<>();
        u1.eq("user_id", userId);
        u1.eq("device_id", deviceId);
        if (userDevice.getTrusteeship()) {
            // 那么关闭托管
            u1.set("trusteeship", false);
        } else {
            // 那么开启托管
            u1.set("trusteeship", true);
            this.smsService.trusteeshipSms(userId, deviceId);
        }
        this.userDeviceService.update(u1);
        return ResponseFormat.success();
    }

    /**
     * 给某台机器设置定时
     */
    @PostMapping("/timed-task/add")
    @ApiOperation("为某台机器设置定时任务。 || 和修改是一体的,再次添加时,会删除后再添加")
    public ResponseFormat addTimeTask(@RequestBody AddTimeTaskBo timeTaskBo) {
        //先查验自己是否拥有此台机器? 先删除后添加
        Integer userId = MySecurity.getUserId();
        Integer deviceId = timeTaskBo.getDeviceId();

        ResponseFormat rsf = this.validDoTimeTask(userId, deviceId);
        if (rsf.getCode() == ResponseCode.ERROR.getCode()) {
            return rsf;
        }

        //默认删除
        QueryWrapper<MonthlyTimedTask> q2 = new QueryWrapper<>();
        q2.eq("device_id", deviceId);
        this.timedTaskService.remove(q2);
        //再添加
        MonthlyTimedTask monthlyTimedTask = new MonthlyTimedTask(deviceId);
        TimedTask timedTask = new TimedTask();
        for (AddTimeTaskBo.TimeSlot slot : timeTaskBo.getList()) {
            if (!timedTask.addTimeNode(slot.getStartDate(), slot.getEndDate())) {
                return ResponseFormat.fail("时间段不符合规则");
            }
        }
        monthlyTimedTask.setTimedTask(timedTask);
        this.timedTaskService.save(monthlyTimedTask);
        return ResponseFormat.success();
    }

    /**
     * 启动自己的定时任务
     */
    @GetMapping("/time-task/open/{id}")
    @ApiOperation("改变自己的定时任务。  ||    启动则关闭  关闭则启动")
    @ForbidMultipleClick(key = "#id", prefixUserId = true, durationSecondsTime = 10)
    public ResponseFormat openTimeTask(@PathVariable("id") Integer id) {
        Integer userId = MySecurity.getUserId();
        MonthlyTimedTask monthlyTimedTask = this.timedTaskService.getById(id);
        if (monthlyTimedTask == null) {
            //定时任务不存在 or 机器不可用
            return ResponseFormat.fail("定时任务不存在");
        }

        ResponseFormat rsf = this.validDoTimeTask(userId, monthlyTimedTask.getDeviceId());
        if (rsf.getCode() == ResponseCode.ERROR.getCode()) {
            return rsf;
        }

        //启动则关闭  关闭则启动
        if (monthlyTimedTask.getOpen()) {
            //启动状态,则关闭
            this.delayTimedTaskService.closeTimeTask(monthlyTimedTask);
            //顺便关闭托管状态
            UpdateWrapper<MonthlyUserDevice> u1 = new UpdateWrapper<>();
            u1.set("trusteeship", false);
            u1.eq("user_id", userId);
            u1.eq("device_id", monthlyTimedTask.getDeviceId());
            this.userDeviceService.update(u1);
        } else {
            this.stringRedisTemplate.delete(monDStatus + monthlyTimedTask.getDeviceId());
            //关闭状态,则启动
            this.delayTimedTaskService.openTimeTask(monthlyTimedTask);
        }
        return ResponseFormat.success();
    }

    private MonthlyUserDevice getUserDevice(Integer userId, Integer deviceId) {
        QueryWrapper<MonthlyUserDevice> q1 = new QueryWrapper<>();
        q1.select("id");
        q1.eq("device_id", deviceId);
        q1.eq("user_id", userId);
        q1.eq("can_use", true);
        return this.userDeviceService.getOne(q1);
    }

    private boolean isTimeTaskDevice(Integer deviceId) {
        //如果当前机器是定时任务状态
        QueryWrapper<MonthlyTimedTask> q1 = new QueryWrapper<>();
        q1.eq("device_id", deviceId);
        MonthlyTimedTask monthlyTimedTask = this.timedTaskService.getOne(q1);
        //定时任务开启中
        return monthlyTimedTask != null && monthlyTimedTask.getOpen();
    }

    private ResponseFormat validDoTimeTask(Integer userId, Integer deviceId) {
        QueryWrapper<MonthlyUserDevice> q1 = new QueryWrapper<>();
        q1.select("trusteeship", "can_use");
        q1.eq("user_id", userId);
        q1.eq("device_id", deviceId);
        MonthlyUserDevice userDevice = this.userDeviceService.getOne(q1);
        if (userDevice == null) {
            return ResponseFormat.fail("未拥有此台机器");
        }
        if (!userDevice.getCanUse()) {
            return ResponseFormat.fail("此机器暂时未通过审核,不可用");
        }
        if (userDevice.getTrusteeship()) {
            return ResponseFormat.fail("请关闭托管后再操作");
        }
        return ResponseFormat.success();
    }

}
